﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;

namespace ComboBoxExpand
{
    public partial class StComboBox : System.Windows.Forms.ComboBox
    {
        public StComboBox()
        {
            InitializeComponent();
        }

        public StComboBox(IContainer container)
        {
            container.Add(this);
            InitializeComponent();
        }

        /// <summary>
        /// 加入Items中的数据。
        /// </summary>
        public object InsertItemsData { get; private set; }

        /// <summary>
        /// 将数据加入到Items
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="data"></param>
        /// <param name="eType"></param>
        /// <exception cref="ArgumentException">数据类型错误</exception>
        ///  <exception cref="ArgumentNullException">数据为空</exception>
        public void EidtItems<T>(T data, DataInsertType eType = DataInsertType.Add)
        {
            if(data==null)
                throw new ArgumentNullException("参数data为空!");
            var tempData = GetNeedData(data);
            if (tempData == null)
                throw new ArgumentNullException("需要添加的数据为Null!");
            if(tempData.Length==0)
                throw new ArithmeticException("获取所需数据错误!");

            SetObjectArray(tempData, eType);
        }

        /// <summary>
        /// 将Dictionary数据添加入Items
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="data"></param>
        /// <param name="keyOrValue">加入Key数据还是Value数据(true为选择Key作为数据源)</param>
        /// <param name="eType"></param>
        public void EditItemsForDictionary<T>(T data, bool keyOrValue, DataInsertType eType = DataInsertType.Add) where T : IDictionary
        {
            if(data==null)
                throw new ArgumentException("参数data为空！");
            if (data.GetType().GetInterfaces().Where(p => p == typeof(IDictionary)).Count() <= 0)
                throw new ArgumentException("数据源信息错误，非Dictionary数据！");

            List<object> tempData = new List<object>();

            foreach (DictionaryEntry item in (data as IDictionary))
            {
                if (keyOrValue)
                    tempData.Add(item.Key);
                else
                    tempData.Add(item.Value);
            }

            EidtItems(tempData);
        }

        /// <summary>
        /// 处理中心（执行eType所选类型事件）
        /// </summary>
        /// <param name="objArray"></param>
        /// <param name="eType"></param>
        protected void SetObjectArray(object[] objArray, DataInsertType eType)
        {
            switch (eType)
            {
                case DataInsertType.Add:
                    this.Items.AddRange(objArray);
                    break;
                case DataInsertType.Delete:
                    {
                        foreach (var item in objArray)
                        {
                            var index = this.Items.ContainsExtension(item);
                            if (index > -1)
                                this.Items.RemoveAt(index);
                        }
                        break;
                    }
                case DataInsertType.ReSet:
                    {
                        this.Items.Clear();
                        this.Items.AddRange(objArray);
                        break;
                    }
                default:
                    this.Items.AddRange(objArray);
                    break;
            }
        }

        /// <summary>
        /// 获取要显示的数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="data"></param>
        /// <returns></returns>
        protected object[] GetNeedData<T>(T data)
        {
            try
            {
                if (data.GetType().GetInterfaces().Where(p => p == typeof(IDictionary)).Count() > 0)
                    throw new ArgumentException("Dictionary 类参数不适用该方法。");

                if (!(data is Enum))//Enum特殊
                {
                    #region 非Enum操作
                    List<PropertyInfo> argumentProperties = new List<PropertyInfo>();//定义一个属性数组数据
                    bool isIEnumerable = false;//是否属于是数组
                    if (data.GetType().GetInterfaces().Where(p => p == typeof(IList)).Count() > 0)//判断是否是数组
                    {
                        isIEnumerable = true;
                        var genericArguments = data.GetType().GetGenericArguments();
                        if (genericArguments.Length > 0)
                            argumentProperties = data.GetType().GetGenericArguments().First().GetProperties().ToList();
                        else
                        {
                            return GetNeedDataForArray(data);
                        }
                    }
                    else
                        argumentProperties = data.GetType().GetProperties().ToList();

                    PropertyInfo properInfo = null;//带有ShowInComboboxAttribute 特性的属性值

                    if (argumentProperties.Count == 0)
                    { }

                    foreach (var item in argumentProperties)//筛选属性
                    {
                        var attribute = item.GetCustomAttributes(false).Where(p => p.GetType() == typeof(ShowInComboboxAttribute));
                        if (attribute.Count() > 0)
                        {
                            properInfo = item;
                            break;
                        }
                    }
                    if (isIEnumerable)
                        return GetNeedDataForIEnumerable((data as IList), properInfo);
                    else
                        return GetNeedDataForObject(data, properInfo);
                    #endregion
                }
                else
                    return GetNeedDataForEnum(data);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// 获取要显示的数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="data"></param>
        /// <returns></returns>
        private object[] GetNeedDataForArray<T>(T data)
        {
            List<object> objList = new List<object>();
            foreach (var item in (data as IList))
            {
                var properties = item.GetType().GetProperties();
                if (item.GetType().Name.ToLower() == "string")//string 做特殊处理
                {
                    objList.Add(item);
                    continue;
                }
                if (properties.Length <= 0)
                {
                    objList.Add(item);
                }
                else
                {
                    foreach (var property in properties)
                    {
                        var attribute = property.GetCustomAttributes(false).Where(p => p.GetType() == typeof(DescriptionAttribute));
                        if (attribute.Count() > 0)
                        {
                            var description = property.GetCustomAttributes(false).Single(p => p.GetType() == typeof(ShowInComboboxAttribute));
                            var name = (description as ShowInComboboxAttribute).DescriptionName;
                            if (!string.IsNullOrEmpty(name))
                                objList.Add(name);
                            else
                                objList.Add(property.GetValue(item, null));
                        }
                    }
                }
            }
            return objList.ToArray();
        }

        /// <summary>
        /// 获取要显示的数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="data"></param>
        /// <returns></returns>
        private object[] GetNeedDataForEnum<T>(T data)
        {
            List<object> objList = new List<object>();
            var fields = data.GetType().GetFields();
            foreach (var item in fields)
            {
                if (item.FieldType != typeof(int))
                {
                    if (item.GetCustomAttributes(false).Where(p => p.GetType() == typeof(ShowInComboboxAttribute)).Count() > 0)
                    {
                        var description = item.GetCustomAttributes(false).Single(p => p.GetType() == typeof(ShowInComboboxAttribute));
                        var name = (description as ShowInComboboxAttribute).DescriptionName;
                        if (!string.IsNullOrEmpty(name))
                            objList.Add(name);
                    }
                    else
                        objList.Add(item.Name);
                }
            }
            return objList.ToArray();
        }

        /// <summary>
        /// 获取要显示的数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="data"></param>
        /// <param name="showProperty"></param>
        /// <returns></returns>
        private object[] GetNeedDataForObject<T>(T data, PropertyInfo showProperty)
        {
            List<object> tempDataList = new List<object>();
            if (showProperty != null)
            {
                var showAttribute = showProperty.GetCustomAttributes(false).Single(p => p.GetType() == typeof(ShowInComboboxAttribute));
                if (string.IsNullOrEmpty((showAttribute as ShowInComboboxAttribute).DescriptionName))
                {
                    var itemVale = showProperty.GetValue(data, null);
                    tempDataList.Add(itemVale);
                }
                else
                    tempDataList.Add((showAttribute as ShowInComboboxAttribute).DescriptionName);
            }
            else
            {
                tempDataList.Add(data);
            }
            return tempDataList.ToArray();
        }

        /// <summary>
        /// 获取要显示的数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="data"></param>
        /// <param name="showProperty"></param>
        /// <returns></returns>
        private object[] GetNeedDataForIEnumerable<T>(T data, PropertyInfo showProperty) where T : IList
        {
            object[] tempDataList = new object[data.Count];

            for (int i = 0; i < data.Count; i++)
            {
                if (showProperty == null)
                {
                    tempDataList[i] = data[i];
                    continue;
                }
                var showAttribute = showProperty.GetCustomAttributes(false).SingleOrDefault(p => p.GetType() == typeof(ShowInComboboxAttribute));
                if (string.IsNullOrEmpty((showAttribute as ShowInComboboxAttribute).DescriptionName))
                {
                    var itemVale = showProperty.GetValue(data, null);
                    tempDataList[i] = itemVale;
                }
                else
                    tempDataList[i] = (showAttribute as ShowInComboboxAttribute).DescriptionName;
            }
            return tempDataList;
        }

        /// <summary>
        /// 数据添加类型
        /// </summary>
        public enum DataInsertType
        {
            /// <summary>
            /// 在原有数据上继续添加
            /// </summary>
            Add,
            /// <summary>
            /// 删除传入的数据
            /// </summary>
            Delete,
            /// <summary>
            /// 将数据重置为当前数据
            /// </summary>
            ReSet,
        }
    }
}
